package com.jzo2o.health.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.db.DbRuntimeException;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.orders.dto.response.OrderResDTO;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.model.dto.response.OrderCancelDTO;
import com.jzo2o.health.model.dto.response.OrderUpdateStatusDTO;
import com.jzo2o.health.service.IOrdersCanceledService;
import com.jzo2o.health.service.IOrdersManagerService;
import com.jzo2o.health.service.IOrdersRefundService;
import com.jzo2o.health.service.IReservationSettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 下单取消类
 * </p>
 *
 * @author itcast
 * @since 2023-07-10
 */
@Slf4j
@Service
public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersManagerService {
    @Resource
    private IOrdersManagerService currentProxy;
    @Resource
    private IOrdersCanceledService ordersCanceledService;
    @Resource
    private IOrdersRefundService ordersRefundService;
    @Resource
    private RefundRecordApi refundRecordApi;
    @Resource
    private IReservationSettingService reservationSettingService;

    @Override
    public Orders queryById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public void cancel(OrderCancelDTO dto) {

        Orders orders = getById(dto.getId());
        if (orders == null) {
            throw new CommonException("订单不存在");
        }

        if (orders.getReservationDate().isBefore(LocalDate.now())) {
            throw new BadRequestException("预约已过期");
        }

        //判断订单状态
        Integer ordersStatus = orders.getOrderStatus();
        if (ObjectUtils.equal(ordersStatus, OrderStatusEnum.NO_PAY.getStatus())) {
            //未支付的订单
            currentProxy.cancelNoPayOrder(dto);
        }else if (ObjectUtils.equal(ordersStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus())){
            //↓↓↓↓↓将交易单号和实付金额拷贝到orderCancelDTO里↓↓↓↓↓
            dto.setTradingOrderNo(orders.getTradingOrderNo());
            dto.setRealPayAmount(orders.getSetmealPrice());
            //↓↓↓↓↓关闭派单中的订单↓↓↓↓↓
            currentProxy.cancelDispatchingOrder(dto);
            //↓↓↓↓↓异步处理退款↓↓↓↓↓
            new Thread(()->{
                //查询退款记录
                OrdersRefund ordersRefund = ordersRefundService.getById(dto.getId());
                if(ObjectUtil.isNotNull(ordersRefund)){
                    //请求退款
                    requestRefundOrder(ordersRefund);
                }
            }).start();
        }else{
            throw new CommonException("当前状态不能取消订单");
        }
    }

    public void requestRefundOrder(OrdersRefund ordersRefund){
        //调用第三方进行退款
        ExecutionResultResDTO executionResultResDTO = refundRecordApi.refundTrading(ordersRefund.getTradingOrderNo(), ordersRefund.getRealPayAmount());
        //如果支付服务中找不到交易单号，直接结束
        if(executionResultResDTO==null){
            return;
        }
        //回更已预约人数
        reservationSettingService.updateCount(ordersRefund.getId());
        //退款后处理订单相关信息
        currentProxy.refundOrder(ordersRefund, executionResultResDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(OrdersRefund ordersRefund, ExecutionResultResDTO executionResultResDTO) {
        //根据响应结果更新退款状态
        int refundStatus;//退款中
        if (ObjectUtil.equal(RefundStatusEnum.SUCCESS.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款成功
            refundStatus = OrderPayStatusEnum.REFUND_SUCCESS.getStatus();
        } else if (ObjectUtil.equal(RefundStatusEnum.FAIL.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款失败
            refundStatus = OrderPayStatusEnum.REFUND_FAIL.getStatus();
        }else{
            refundStatus = OrderPayStatusEnum.REFUNDING.getStatus();
        }

        //如果是退款中状态，程序结束
        if (ObjectUtil.equal(refundStatus, OrderPayStatusEnum.REFUNDING.getStatus())) {
            return;
        }

        //非退款中状态，更新订单的退款状态
        boolean updated = lambdaUpdate()
                .set(Orders::getPayStatus, refundStatus)
                .set(Orders::getRefundId, executionResultResDTO.getRefundId())
                .set(Orders::getRefundNo, executionResultResDTO.getRefundNo())
                .ne(Orders::getPayStatus, refundStatus)
                .eq(Orders::getId, ordersRefund.getId())
                .update();
        //删除申请退款记录，删除后定时任务不再扫描
        if(updated){
            //非退款中状态，删除申请退款记录，删除后定时任务不再扫描
            ordersRefundService.removeById(ordersRefund.getId());
        }
    }

    @Override
    public List<Orders> queryOverTimePayOrdersListByCount(Integer count) {
        //根据订单创建时间查询超过15分钟未支付的订单
        return lambdaQuery()
                //查询待支付状态的订单
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                //查询15分钟之前下的订单，即下单时间早于 15分钟之前的时间
                .lt(Orders::getCreateTime, LocalDateTime.now().minusMinutes(15))
                //查询一定数量的订单，而不是所有
                .last("limit " + count)
                .list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelNoPayOrder(OrderCancelDTO dto) {
        //保存取消订单记录
        OrdersCancelled ordersCanceled = BeanUtil.toBean(dto, OrdersCancelled.class);
        ordersCanceled.setCancellerId(dto.getCurrentUserId());
        ordersCanceled.setCancellerName(dto.getCurrentUserName());
        ordersCanceled.setCancellerType(dto.getCurrentUserType());
        ordersCanceled.setCancelTime(LocalDateTime.now());
        ordersCanceledService.save(ordersCanceled);
        //更新订单状态为取消订单
        OrderUpdateStatusDTO orderUpdateStatusDTO = OrderUpdateStatusDTO.builder()
                .id(dto.getId())
                .originStatus(OrderStatusEnum.NO_PAY.getStatus())
                .targetStatus(OrderStatusEnum.CANCELLED.getStatus())
                .build();

        int result = currentProxy.updateStatus(orderUpdateStatusDTO);
        if (result <= 0) {
            throw new DbRuntimeException("订单取消事件处理失败");
        }else {
            reservationSettingService.updateCount(dto.getId());
        }
    }

    /**
     * <p>
     * 订单表 服务实现类
     * </p>
     *
     * @author itcast
     * @since 2023-08-02
     */
    @Override
    public Integer updateStatus(OrderUpdateStatusDTO orderUpdateStatusReqDTO) {
        LambdaUpdateWrapper<Orders> updateWrapper = Wrappers.<Orders>lambdaUpdate()
                .eq(Orders::getId, orderUpdateStatusReqDTO.getId())
                .gt(Orders::getMemberId, 0)
                .eq(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getOriginStatus()),Orders::getOrderStatus,orderUpdateStatusReqDTO.getOriginStatus())
                .set(Orders::getOrderStatus, orderUpdateStatusReqDTO.getTargetStatus())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getPayStatus()),Orders::getPayStatus,orderUpdateStatusReqDTO.getPayStatus())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getPayTime()),Orders::getPayTime,orderUpdateStatusReqDTO.getPayTime())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getReservationDate()),Orders::getReservationDate,orderUpdateStatusReqDTO.getReservationDate())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getTradingOrderNo()),Orders::getTradingOrderNo,orderUpdateStatusReqDTO.getTradingOrderNo())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getTransactionId()),Orders::getTransactionId,orderUpdateStatusReqDTO.getTransactionId())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getTradingChannel()),Orders::getTradingChannel,orderUpdateStatusReqDTO.getTradingChannel())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getRefundId()),Orders::getRefundId,orderUpdateStatusReqDTO.getRefundId())
                .set(ObjectUtil.isNotNull(orderUpdateStatusReqDTO.getRefundNo()),Orders::getRefundNo,orderUpdateStatusReqDTO.getRefundNo());

        boolean update = super.update(updateWrapper);
        return update?1:0;
    }

    @Override
    public OrderResDTO getDetail(Long id) {
        Orders orders = queryById(id);
        //↓↓↓↓如果支付过期则取消订单↓↓↓↓
        boolean canceled = cancelOrderIfPayOverTime(orders);
        if (canceled) {
            orders = queryById(id);
        }

        OrderResDTO orderResDTO = BeanUtil.toBean(orders, OrderResDTO.class);
        return orderResDTO;
    }

    /**
     * 如果订单超时未支付，就取消订单
     * @param orders
     * @return true取消了，false未取消
     */
    private boolean cancelOrderIfPayOverTime(Orders orders) {
        if (ObjectUtils.equal(orders.getPayStatus(), OrderPayStatusEnum.NO_PAY.getStatus())
                && orders.getCreateTime().isBefore(LocalDateTime.now().minusMinutes(15))) {
            //超时未支付，取消订单
            OrderCancelDTO dto = BeanUtil.toBean(orders, OrderCancelDTO.class);
            dto.setCancelReason("超时未支付自动取消");
            dto.setCurrentUserType(UserType.SYSTEM);
            currentProxy.cancelNoPayOrder(dto);
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor=Exception.class)
    public void cancelDispatchingOrder(OrderCancelDTO dto) {
        //添加订单取消记录
        OrdersCancelled ordersCanceled = BeanUtils.toBean(dto,OrdersCancelled.class);
        ordersCanceled.setCancellerId(dto.getCurrentUserId());
        ordersCanceled.setCancellerName(dto.getCurrentUserName());
        ordersCanceled.setCancellerType(dto.getCurrentUserType());
        ordersCanceled.setCancelTime(LocalDateTime.now());
        ordersCanceledService.save(ordersCanceled);

        //修改订单状态为已关闭
        OrderUpdateStatusDTO orderUpdateStatusReqDTO = new OrderUpdateStatusDTO();
        orderUpdateStatusReqDTO.setId(dto.getId());
        //原始状态-派单中
        orderUpdateStatusReqDTO.setOriginStatus(OrderStatusEnum.WAITING_CHECKUP.getStatus());
        //目标状态-已关闭
        orderUpdateStatusReqDTO.setTargetStatus(OrderStatusEnum.CLOSED.getStatus());
        //设置退款状态为1退款中
        orderUpdateStatusReqDTO.setPayStatus(OrderPayStatusEnum.REFUNDING.getStatus());
        Integer integer = currentProxy.updateStatus(orderUpdateStatusReqDTO);
        if(integer<=0){
            throw new DbRuntimeException("订单取消事件处理失败");
        }

        //添加待退款记录
        OrdersRefund ordersRefund = BeanUtils.toBean(dto, OrdersRefund.class);
        ordersRefundService.save(ordersRefund);
    }

}
